#include "SensitiveFilter.h"
#include "Utils.h"

#include <iostream>

namespace Utils
{
    struct SensitiveNode
    {
        char data;
        bool last;
        SensitiveNode *sibling;
        SensitiveNode *next;
    };

    SensitiveFilter::SensitiveFilter() {}
    SensitiveFilter::~SensitiveFilter()
    {
        freeNode(root);
    }

    void SensitiveFilter::freeNode(SensitiveNode *node)
    {
        if (node != nullptr)
        {
            freeNode(node->next);
            freeNode(node->sibling);
            delete node;
        }
    }

    SensitiveNode *SensitiveFilter::nodeHasExist(SensitiveNode *node, char data)
    {
        while (node != nullptr)
        {
            if (node->data == data)
            {
                return node;
            }
            node = node->sibling;
        }
        return nullptr;
    }

    void SensitiveFilter::loadTextData(const std::string &text)
    {
        freeNode(root);

        std::list<std::string> splitStr;
        Utils::StringSplit(text, "@", splitStr);

        // std::cout << "屏蔽词数量: " << splitStr.size() << std::endl;
        // for(const std::string &word : splitStr)
        // {
        //     std::cout << word << std::endl;
        // }

        root = new SensitiveNode;
        root->next = nullptr;
        root->sibling = nullptr;
        root->data = 0;
        SensitiveNode *curNode = root;

        for (const std::string &wordText : splitStr)
        {
            for (int32_t index = 0; index < wordText.length(); ++index)
            {
                // check char node does exist in curNode->next link list
                SensitiveNode *node = nodeHasExist(curNode->next, wordText[index]);
                if (node == nullptr)
                {
                    node = new SensitiveNode;
                    node->data = wordText[index];
                    node->last = false;
                    node->next = nullptr;
                    node->sibling = nullptr;
                    if (curNode->next == nullptr)
                    {
                        curNode->next = node;
                    }
                    else
                    {
                        SensitiveNode *temp = curNode->next;
                        while (temp->sibling != nullptr)
                        {
                            temp = temp->sibling;
                        }
                        temp->sibling = node;
                    }
                }
                // make curNode point at node
                curNode = node;
            }
            // if is the end of word,set sign at the last,because it may has many branches
            curNode->last = true;
            curNode = root;
        }
    }

    bool SensitiveFilter::filterContent(std::string &content)
    {
        if (root == nullptr || root->next == nullptr)
        {
            return false;
        }
        SensitiveNode *curNode = root->next;
        int32_t start = -1;
        // stringstream ss;
        bool shouldReview = false;
        bool result = false;
        for (int32_t index = 0; index < content.length(); index++)
        {
            // traversal content

            bool hasfind = false; // if hasfind,find next char

            char ch = content[index];

            while (curNode != 0)
            {
                if (curNode->data == ch)
                {
                    hasfind = true;
                    if (start == -1)
                    {
                        // first time find char ,record first time index
                        start = index;
                    }
                    if (curNode->last && curNode->next == 0)
                    {
                        // it has arrived at last branch
                        for (; start <= index; ++start)
                        {
                            content[start] = '*';
                        }
                        result = true;
                        start = -1;
                        curNode = root->next;
                        shouldReview = false;
                    }
                    else if (curNode->last)
                    {
                        // it may not arrived at last branch
                        for (; start <= index; ++start)
                        {
                            content[start] = '*';
                        }
                        result = true;
                        start = index + 1;
                        curNode = curNode->next;
                        shouldReview = true;
                    }
                    else
                    {
                        curNode = curNode->next;
                    }
                    break;
                }
                curNode = curNode->sibling;
            }

            if (shouldReview && !hasfind)
            {
                index = start - 1; // this time is checking curNode->next,it should also check root->next,start-1 because of i++
                shouldReview = false;
                start = -1;
                curNode = root->next;
            }
            else if (!hasfind)
            {
                if (start > -1)
                {
                    index = start; // start must have checked with root->next,so it was not used to be -1
                }
                start = -1;
                curNode = root->next;
            }
        }
        return result;
    }

    void SensitiveFilter::loadFile(const std::string &path)
    {
        std::string text;
        if (Utils::LoadTextFile(path, text))
        {
            loadTextData(text);
        }
    }
}
